package test.my.com.myapplicationtest.gesture_lock_view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import java.util.ArrayList;
import java.util.List;

import test.my.com.myapplicationtest.R;

/**
 * Author : Cooper
 * Time : 2017/4/1  17:36
 * Description : 手势密码 带图标
 */

public class GestureLockIconViewGroup extends ViewGroup {

    private static final int DEFAULT_ICON_SPACE = 50;
    private static final String DEFAULT_SELECT_LINE_COLOR = "#E6D28F";
    private static final int DEFAULT_ATTEMPT_NUM = 5;
    private static final int DEFAULT_WIDTH_HEIGHT = 80;
    private Context mContext;

    private int mDefaultIcon; // 默认图标
    private int mSelectIcon;  // 选中图片
    private int mIconSpace;   // 图标间距
    private int mIconWidthHeight;   // 图标宽高
    private int mAttemptNum = 5;  // 尝试次数
    private String mSelectLineColor = "#E6D28F";  // 连接线颜色

    private List<Integer> mChoose = new ArrayList<Integer>();
    private Paint mPathPaint;
    private Paint mBitmapPaint;
    private Bitmap mSelectBitmap;
    private Rect mSrcRect = new Rect();
    private Path mPath;

    /**
     * 指引线的开始位置x
     */
    private int mLastPathX;
    /**
     * 指引线的开始位置y
     */
    private int mLastPathY;
    /**
     * 指引下的结束位置
     */
    private Point mTmpTarget = new Point();
    private List<Point> mBitmapPointList = new ArrayList<>();
    /**
     * 存储答案
     */
    private List<Integer> mAnswer = new ArrayList<Integer>();

    private OnGestureLockIconViewListener mOnGestureLockIconViewListener;
    /**
     * 判断是否是第一次设置
     *是否改变子元素的状态为UP
     */
    private  boolean isFrist =true;

    public  enum  DetectionReult{
        NumNot,Pass,Reject,ACTION_DOWN,Frist
    }

    public GestureLockIconViewGroup(Context context) {
        super(context);
    }

    public GestureLockIconViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GestureLockIconViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GestureLockIconViewGroup, defStyleAttr, 0);
        int n = ta.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = ta.getIndex(i);
            switch (attr) {
                case R.styleable.GestureLockIconViewGroup_defaultIcon:
                    this.mDefaultIcon = ta.getResourceId(attr, R.drawable.ic_password_default);
                    break;
                case R.styleable.GestureLockIconViewGroup_selectIcon:
                    this.mSelectIcon = ta.getResourceId(attr, R.drawable.ic_password_onclick);
                    break;
                case R.styleable.GestureLockIconViewGroup_iconSpace:
                    this.mIconSpace = ta.getDimensionPixelOffset(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_ICON_SPACE,
                            getResources().getDisplayMetrics()));
                    break;
                case R.styleable.GestureLockIconViewGroup_selectLineColor:
                    this.mSelectLineColor = ta.getString(attr);
                    break;
                case R.styleable.GestureLockIconViewGroup_attemptNum:
                    this.mAttemptNum = ta.getInt(attr, DEFAULT_ATTEMPT_NUM);
                    break;
                case R.styleable.GestureLockIconViewGroup_iconWidthHeight:
                    this.mIconWidthHeight = ta.getDimensionPixelOffset(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_WIDTH_HEIGHT,
                            getResources().getDisplayMetrics()));
                    break;

            }
        }
        ta.recycle();

        // 初始化画笔
        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPathPaint.setStyle(Paint.Style.STROKE);
        mPathPaint.setStrokeWidth(20);
        mPathPaint.setStrokeCap(Paint.Cap.ROUND);
        mPathPaint.setStrokeJoin(Paint.Join.ROUND);
        mPathPaint.setColor(Color.parseColor(mSelectLineColor));
        mPath = new Path();

        mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBitmapPaint.setFilterBitmap(true);
        mBitmapPaint.setDither(true);

        mSelectBitmap = ((BitmapDrawable) mContext.getResources().getDrawable(mSelectIcon))
                .getBitmap();
        mSrcRect.set(0,0,mSelectBitmap.getWidth(),mSelectBitmap.getHeight());
        addIconView();
    }

    public void addIconView() {
        for (int i = 0; i < 9; i++) {
            ImageView iv = new ImageView(mContext);
            iv.setScaleType(ImageView.ScaleType.CENTER_CROP);
            iv.setImageResource(mDefaultIcon);
            iv.setId(i);
            addView(iv);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 获得它的父容器为它设置的测量模式和大小
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        // 容器总宽度
        int vgWidth = 0;
        // 容器总高度
        int vgHeight = 0;

        // 子view总数
        int viewCount = getChildCount();

        if (mIconWidthHeight == 0) {
            View child = getChildAt(0);
            int wh = View.MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            child.measure(wh, wh);
            mIconWidthHeight = child.getMeasuredWidth();
        }

        for (int i = 0; i < viewCount; i++) {
            View child = getChildAt(i);

            ContainerLayoutParams clp = (ContainerLayoutParams) child.getLayoutParams();
            clp.cLeft = (i % 3) * (mIconWidthHeight + mIconSpace);
            clp.cTop = (i / 3) * (mIconWidthHeight + mIconSpace);

        }
        vgWidth = vgHeight = ((viewCount - 1) / 3 + 1) * mIconWidthHeight + (viewCount - 1) / 3 * mIconSpace;

        setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth
                : vgWidth, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight
                : vgHeight);
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        int viewCount = getChildCount();
        for (int i = 0; i < viewCount; i++) {
            View child = getChildAt(i);
            ContainerLayoutParams clp = (ContainerLayoutParams) child.getLayoutParams();
            child.layout(clp.cLeft, clp.cTop, clp.cLeft + mIconWidthHeight,
                    clp.cTop + mIconWidthHeight);
        }
    }

    @Override
    public void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        //绘制GestureLockView间的连线
        if (mPath != null) {
            canvas.drawPath(mPath, mPathPaint);
        }
        //绘制指引线
        if (mChoose.size() > 0) {
            if (mLastPathX != 0 && mLastPathY != 0)
                canvas.drawLine(mLastPathX, mLastPathY, mTmpTarget.x,
                        mTmpTarget.y, mPathPaint);
        }

        if (mBitmapPointList.size() > 0) {
            for (Point point : mBitmapPointList) {
                Rect ditRect = new Rect();
                ditRect.set(point.x,point.y,point.x+mIconWidthHeight,point.y+mIconWidthHeight);
                canvas.drawBitmap(mSelectBitmap,mSrcRect,ditRect,mBitmapPaint);
            }
        }

    }

    /**
     * 做一些必要的重置
     */
    public void reset() {
        mChoose.clear();
        mPath.reset();
        mBitmapPointList.clear();
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (mOnGestureLockIconViewListener != null) {
                    mOnGestureLockIconViewListener.onGestureEvent(DetectionReult.ACTION_DOWN);
                }
                // 重置
                reset();
                break;
            case MotionEvent.ACTION_MOVE:
                View child = getChildIdByPos(x, y);
                if (child != null) {
                    int cId = child.getId();
                    if (!mChoose.contains(cId)) {
                        mChoose.add(cId);
                        if (mOnGestureLockIconViewListener != null) {
                            mOnGestureLockIconViewListener.onBlockSelected(cId);
                        }
                        // 设置指引线的起点
                        mLastPathX = child.getLeft() / 2 + child.getRight() / 2;
                        mLastPathY = child.getTop() / 2 + child.getBottom() / 2;

                        Point bitPoint = new Point();
                        bitPoint.x= child.getLeft();
                        bitPoint.y = child.getTop();
                        mBitmapPointList.add(bitPoint);

                        if (mChoose.size() == 1)// 当前添加为第一个
                        {
                            mPath.moveTo(mLastPathX, mLastPathY);
                        } else
                        // 非第一个，将两者使用线连上
                        {
                            mPath.lineTo(mLastPathX, mLastPathY);
                        }
//                        child.setMode(Mode.STATUS_FINGER_ON);
                    }
                }
                // 指引线的终点
                mTmpTarget.x = x;
                mTmpTarget.y = y;
                break;
            case MotionEvent.ACTION_UP:

                this.mAttemptNum--;

                // 回调是否成功
                if (mOnGestureLockIconViewListener != null && mChoose.size() > 0 ) {

                    mOnGestureLockIconViewListener.onGestureEvent(checkAnswer());
                    if (this.mAttemptNum == 0) {
                        mOnGestureLockIconViewListener.onUnmatchedExceedBoundary();
                    }
                }

                // 将终点设置位置为起点，即取消指引线
                mTmpTarget.x = mLastPathX;
                mTmpTarget.y = mLastPathY;
                break;

        }
        invalidate();
        return true;
    }

    /**
     * 检查用户绘制的手势是否正确
     *
     * @return
     */
    private DetectionReult checkAnswer() {
//        Log.i(TAG, "mAnswer.length:" + mAnswer.length + "  mChoose.size():" + mChoose.size());

        if(mChoose.size()<4){
            reset();
            return DetectionReult.NumNot;
        }
        if(isFrist){
            mAnswer.addAll(mChoose);
            isFrist=!isFrist;
            return DetectionReult.Frist;
        }
        if (mAnswer.size() != mChoose.size()){
            reset();
            return DetectionReult.Reject;
        }

        for (int i = 0; i < mAnswer.size(); i++) {
            if (mAnswer.get(i)!= mChoose.get(i)){
                reset();
                return  DetectionReult.Reject;
            }
        }
        if (mOnGestureLockIconViewListener != null) {
            mOnGestureLockIconViewListener.verifyFinish(mAnswer);
        }
        return  DetectionReult.Pass;
    }

    /**
     * 对外公布设置答案的方法
     *
     * @param answer
     */
    public void setAnswer(List<Integer> answer) {
        this.mAnswer = answer;
        if(mAnswer.size()>0){
            isFrist = false;
        }else{
            isFrist = true;
        }
    }

    /**
     * 清理存储的代码
     */
    public  void  cleanAnswer(){
        isFrist=true;
        mAnswer.clear();
    }


    /**
     * 通过x,y获得落入的GestureLockView
     *
     * @param x
     * @param y
     * @return
     */
    private View getChildIdByPos(int x, int y) {
        for (int i = 0;i<getChildCount();i++) {
            View view = getChildAt(i);
            if (checkPositionInChild(view, x, y)) {
                return view;
            }
        }

        return null;

    }

    /**
     * 检查当前左边是否在child中
     *
     * @param child
     * @param x
     * @param y
     * @return
     */
    private boolean checkPositionInChild(View child, int x, int y) {

        //设置了内边距，即x,y必须落入下GestureLockView的内部中间的小区域中，可以通过调整padding使得x,y落入范围不变大，或者不设置padding
        int padding = (int) (mIconWidthHeight * 0.15);

        if (x >= child.getLeft() + padding && x <= child.getRight() - padding
                && y >= child.getTop() + padding
                && y <= child.getBottom() - padding) {
            return true;
        }
        return false;
    }

    @Override
    public android.view.ViewGroup.LayoutParams generateLayoutParams(
            AttributeSet attrs) {
        return new ContainerLayoutParams(getContext(), attrs);
    }

    @Override
    protected android.view.ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new ContainerLayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
    }

    @Override
    protected android.view.ViewGroup.LayoutParams generateLayoutParams(
            android.view.ViewGroup.LayoutParams p) {
        return new ContainerLayoutParams(p);
    }

    @Override
    protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {
        return p instanceof ContainerLayoutParams;
    }


    public static class ContainerLayoutParams extends ViewGroup.LayoutParams {

        public int cLeft = 0;
        public int cTop = 0;

        public ContainerLayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public ContainerLayoutParams(int width, int height) {
            super(width, height);
        }

        public ContainerLayoutParams(LayoutParams source) {
            super(source);
        }
    }

    public interface OnGestureLockIconViewListener {
        /**
         * 单独选中元素的Id
         */
        public void onBlockSelected(int cId);

        /**
         * 是否匹配
         *
         * @param matched
         */
        public void onGestureEvent(DetectionReult matched);

        /**
         * 超过尝试次数
         */
        public void onUnmatchedExceedBoundary();

        /**
         * 验证完成
         */
        public  void  verifyFinish(List<Integer> intArr);

    }
}
